%{
#include <stdlib.h>
#include <stdio.h>
#include "monstp.tab.h"

   int seduce_state = 0;
   FILE* seduce_data = NULL;
   YY_BUFFER_STATE buf = (YY_BUFFER_STATE)0;
   int mon_index = 0;
%}

%x comment string unimplemented preproc seduce

%option yylineno
%option stack
%option nodefault
/*%option debug*/
%%

   /* Handle comments */	
"/*"         			yy_push_state(comment);
<comment>[^*\n]*        /* eat anything that's not a '*' */
<comment>"*"+[^*/\n]*   /* eat up '*'s not followed by '/'s */
<comment>\n             /*++yylineno;*/
<comment>"*"+"/"        yy_pop_state();

#if[ ]0					yy_push_state(unimplemented);
<unimplemented>#endif	yy_pop_state();
<unimplemented>MON		mon_index++;
<unimplemented>.		/* ignore */
<unimplemented>\n		/* ignore */

   /* Ignore many preprocessor directives, including ifdef */
   /* also handle the seduction attack junk */
   /* Seduction attack stuff:  (1) read the macro for SEDUCTION_ATTACKS and write it into a temp file */
   /* (2) when we see SEDUCTION_ATTACKS reappear in the source, jump over and read from our temp file */
   /* (3) when we hit EOL and seduce_state==3, meaning that we're in the temp file, pop the temp file */
   /* and resume normal parsing.  Net effect is to crudely insert the macro. */
#[ \t]*(define|include|undef|else|ifndef|endif)[ \t]*  	yy_push_state(preproc);
<preproc>{
\\\n													/* eat */
\n														yy_pop_state();
SEDUCE													{if (seduce_state==0) seduce_state=1;}
SEDUCTION_ATTACKS[ \t]*									{if (seduce_state==1) { 
														 	yy_push_state(seduce); 
														 	if (!seduce_data) seduce_data = tmpfile();
															seduce_state=2;}}
[^\n]
}
<seduce>\\\n
<seduce>\n						{yy_pop_state(); fflush(seduce_data); yyless(0);}
<seduce>[^\\\n]+				fprintf(seduce_data, "%s", yytext);
<INITIAL>SEDUCTION_ATTACKS		{ if (seduce_state == 2) { 
									rewind(seduce_data);
								  	buf = yy_create_buffer(seduce_data, YY_BUF_SIZE);
								  	yypush_buffer_state(buf);
								   	seduce_state = 3; }}
<INITIAL><<EOF>>				{ if (seduce_state == 3) {
								  	yypop_buffer_state(); 
								  	seduce_state = 2;}}

  /* Manually add #ifdefs that should be ignored here */
#ifdef[ ][A-Z_]+		{ if (strcmp(yytext+7, "CHARON")==0) { yy_push_state(unimplemented); } }

#define[ ]WT_[A-Z_]+     {yylval.c = strdup(yytext+11); return WEIGHT_CONST;}

[(),|]	{ return yytext[0]; }

   /*  Digits */
-?[0-9]+L?     {yylval.i = atoi(yytext); return NUM;}

MON	{ yylval.i = mon_index++;  return MON; }
LVL     { return LVL; }
A	{ return A;}
ATTK	{ return ATTK;}
NO_ATTK { return NO_ATTK;}
SIZ     { return SIZ;}

G_[A-Z]+	{yylval.c = strdup(yytext+2); return GENO;}
S_[A-Z_]+	{yylval.c = strdup(yytext+2); return SYMBOL;}
AT_[A-Z]+	{yylval.c = strdup(yytext+3); return A_TYPE;}
AD_[A-Z]+	{yylval.c = strdup(yytext+3); return A_DAMG;}
MS_[A-Z]+	{yylval.c = strdup(yytext+3); return SOUND;}
MZ_[A-Z]+	{yylval.c = strdup(yytext+3); return SIZE;}
MR_[A-Z]+	{yylval.c = strdup(yytext+3); return RESIST;}
M1_[A-Z_]+	{yylval.c = strdup(yytext+3); return MF1;}
M2_[A-Z_]+	{yylval.c = strdup(yytext+3); return MF2;}
M3_[A-Z_]+	{yylval.c = strdup(yytext+3); return MF3;}
CLR_[A-Z_]+	{yylval.c = strdup(yytext+4); return COLOR;}
HI_[A-Z]+	{yylval.c = strdup(yytext+3); return COLOR;}
DRAGON_[A-Z]+	{yylval.c = strdup(yytext); return COLOR;}
WT_[A-Z]+	{yylval.c = strdup(yytext+3); return WEIGHT;}
A_[A-Z]+	{yylval.c = strdup(yytext+2); return ALIGNMENT;}

  /* sizeof stuff for extended monst data */
"sizeof("  {return '(';}
"struct "[a-z_]+  {yylval.c = strdup(yytext+7); return EXTDATA;}

   /* quoted strings (can't escape quotes within strings) */
\"	yy_push_state(string);
\"\"    {return EMPTY_STRING;}
<string>[^\"]*	{yylval.c = strdup(yytext); return STRING;}
<string>\"  yy_pop_state();

"void NDECL("[a-z_]*");"    /* eat function decls */
"NEARDATA struct permonst mons[] = {"  /*eat list start*/
"struct permonst _mons2[] = {"  /* eat splot kludge */
"};"				/* eat list end */

[ \t]+	/* eat whitespace */

\n  /*++yylineno;*/
%%

int yywrap() {
 return 1;
}
